using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Gumps;
using Server.Targeting;
using Server.Multis;
using Server.ContextMenus;
using Server.Regions;
using Server.Misc;


namespace Server.Mobiles
{
	public class WanderingTrader : BaseVendor, IHardsellable
	{
		private ArrayList m_SBInfos = new ArrayList();
		protected override ArrayList SBInfos{ get { return m_SBInfos; } }

		private VendorManager m_Manager;
		private Mobile m_Owner;
		private Container m_HoldBox;
		private Container m_ShowBox;
		private Type m_Currency;
		private int m_HoldGold;
		private int m_CommRate;
		private bool m_IsComm;
		private bool m_AllowBid;
		private bool m_BondOnly;

		private CurrencyInfo m_CInfo;

		private Hashtable m_ShopItems;
		private List<BidByItem> m_BidItems;

		#region IHardsellable
		public Container HoldBox
		{
			get{ return m_HoldBox; }
			set{ m_HoldBox = value; InvalidateProperties(); }
		}

		public Container ShowBox
		{
			get{ return m_ShowBox; }
			set{ m_ShowBox = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public VendorManager Manager
		{
			get{ return m_Manager; }
			set{ m_Manager = value; InvalidateProperties(); }
		}

		public Hashtable ShopItems
		{
			get{ return m_ShopItems; }
			set{ m_ShopItems = value; InvalidateProperties(); }
		}

		public Type Currency
		{
			get{ return m_Currency; }
			set{ m_Currency = value; InvalidateProperties(); }
		}

		public CurrencyInfo CInfo
		{
			get{ return m_CInfo; }
			set{ m_CInfo = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public int HoldGold
		{
			get{ return m_HoldGold; }
			set{ m_HoldGold = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public int CommRate
		{
			get{ return m_CommRate; }
			set{ m_CommRate = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public bool IsComm
		{
			get{ return m_IsComm; }
			set{ m_IsComm = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public bool AllowBid
		{
			get{ return ( m_AllowBid && m_Manager != null && m_Manager.AllowBid ); }
			set
			{
				if ( m_Manager != null && m_Manager.AllowBid )
					m_AllowBid = value;
				else
					m_AllowBid = false;

				InvalidateProperties();
			}
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public bool BondOnly
		{
			get{ return m_BondOnly; }
			set{ m_BondOnly = value; InvalidateProperties(); }
		}

		public List<BidByItem> BidItems
		{
			get{ return m_BidItems; }
			set{ m_BidItems = value; InvalidateProperties(); }
		}

		public Mobile Owner
		{
			get{ return m_Owner; }
			set{ m_Owner = value; InvalidateProperties(); }
		}
		#endregion


		[Constructable]
		public WanderingTrader( Mobile owner, VendorManager vm ) : this( owner, vm, "the Wandering Trader" )
		{
		}

		[Constructable]
		public WanderingTrader( Mobile owner, VendorManager vm, string title ) : base( title )
		{
			this.Title = title;
			m_AllowBid = true;
			m_BondOnly = true;

			m_Owner = owner;
			m_Manager = vm;

			Item pack = FindItemOnLayer( Layer.Backpack );
			
			if ( pack != null )
			{
				RemoveItem( pack );
				pack.Delete();
			}

			m_ShowBox = new VendorBox();
			m_ShowBox.Movable = false;

			AddItem( m_ShowBox );

			Blessed = true;
			m_BidItems = new List<BidByItem>();

			m_ShopItems = new Hashtable();
			m_Currency = typeof( Gold );
			m_CInfo = new CurrencyInfo( 0xEEF, 0, false );

			m_IsComm = true;
			m_CommRate = 0;
			m_HoldGold = 10;

			m_HoldBox = new VendorBox();
			m_HoldBox.Movable = false;

			AddItem( m_HoldBox );
		}

		public WanderingTrader( Serial serial ) : base( serial )
		{
		}

		public override void InitSBInfo()
		{
		}


		public override void OnThink()
		{
			BaseCreature bc = this as BaseCreature;
			VendorManager vm = m_Manager;

			if ( m_Manager == null || m_Manager.Deleted )
				return;

			int distance = (int)bc.GetDistanceToSqrt( bc.Home );

			if ( m_Manager.AreaRange > 0 && bc.RangeHome > 0 && distance > bc.RangeHome + 10 )
			{
				BaseCreature.TeleportPets( (Mobile)this, bc.Home, m_Manager.Map );

				((Mobile)bc).PlaySound( 0x1FC );
				((Mobile)bc).MoveToWorld( bc.Home, m_Manager.Map );
				((Mobile)bc).PlaySound( 0x1FC );
			}

			base.OnThink();
		}

		public override void OnDelete()
		{
			if ( SaveStone.TradePets != null && SaveStone.TradePets.Count > 0 )
			{
				for ( int i = 0; i < SaveStone.TradePets.Count; i++ )
				{
					TradeMobile tm = SaveStone.TradePets[i] as TradeMobile;

					if ( tm.m_owner == null || tm.m_owner.Deleted )
					{
						Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( RemovePet_Callback ), new object[] { tm.m_pet } );
					}
					else if ( ( tm.m_vendor == null || tm.m_vendor.Deleted ) && !( tm.m_vendor is RestockableVendor ) )
					{
						tm.m_pet.ControlTarget = null;
						tm.m_pet.ControlOrder = OrderType.Stay;
						tm.m_pet.Internalize();

						tm.m_pet.SetControlMaster( null );
						tm.m_pet.SummonMaster = null;
						tm.m_pet.IsStabled = true;
						tm.m_pet.Loyalty = BaseCreature.MaxLoyalty; // Wonderfully happy
						tm.m_owner.Stabled.Add( tm.m_pet );

						SaveStone.TradePets.RemoveAt( i-- );
					}
					else if ( ( tm.m_vendor == null || tm.m_vendor.Deleted ) && tm.m_vendor is RestockableVendor )
					{
						Timer.DelayCall( TimeSpan.Zero, new TimerStateCallback( RemovePet_Callback ), new object[] { tm.m_pet } );
						// TradePets will not be removed here, because there might not be enough time
						// They will be removed in Maintenance.cs
//						SaveStone.TradePets.RemoveAt( i-- );
					}

				}
			}

			base.OnDelete();
		}

		private static void RemovePet_Callback( object state )
		{
			object[] aState = (object[]) state;

			BaseCreature pet = (BaseCreature) aState[0];

			pet.Internalize();
			pet.Delete();
		}

		public override void OnDoubleClick( Mobile from )
		{
			if( CanPaperdollBeOpenedBy( from ) )
				DisplayPaperdollTo( from );
		}


		// to implement IHardsellable
		public virtual bool IsOwner( Mobile m )
		{
			if ( m.AccessLevel >= AccessLevel.GameMaster )
				return true;

			return ( m == Owner );
		}

		public void AddBidItems( Mobile from, BidByItem bbi )
		{
			if ( m_BidItems == null )
				m_BidItems = new List<BidByItem>();

			m_BidItems.Add( bbi );
		}

		public override bool OnBuyItems( Mobile buyer, ArrayList list, Type currency )
		{
			return base.OnBuyItems( buyer, list, m_Currency );
		}

		public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
		{
			if ( from.Alive && !Deleted && ( from.AccessLevel >= AccessLevel.GameMaster || IsOwner( from ) ) )
			{
				list.Add( new SetupVendorEntry( from, this ) );
				list.Add( new AddVendorItemEntry( from, this ) );
			}

			if ( from.Alive && !Deleted )
				list.Add( new BuyVendorItemEntry( from, this ) );

			if ( from.Alive && !Deleted && !( this is RestockableVendor ) )
				list.Add( new ListBidEntry( from, this ) );

			base.GetContextMenuEntries( from, list );
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );
			writer.Write( (int) 0 ); // version

			writer.Write( (Mobile) m_Manager );
			writer.Write( (Mobile) m_Owner );
			writer.Write( (Item) m_HoldBox );
			writer.Write( (Item) m_ShowBox );
			writer.Write( (string) m_Currency.Name );
			writer.Write( (int) m_HoldGold );
			writer.Write( (int) m_CommRate );
			writer.Write( (bool) m_IsComm );
			writer.Write( (bool) m_AllowBid );
			writer.Write( (bool) m_BondOnly );

			writer.Write( (int) m_CInfo.m_itemID );
			writer.Write( (int) m_CInfo.m_hue );
			writer.Write( (bool) m_CInfo.m_dupeicon );

			if ( m_ShopItems != null && m_ShopItems.Count > 0 )
			{
				writer.Write( (int) m_ShopItems.Count );

				foreach ( DictionaryEntry de in m_ShopItems )
				{
					writer.Write( (Item) de.Key );

					TradeItem ti = (TradeItem)de.Value;

					writer.Write( (Item)ti.ItemObj );
					writer.Write( (int)ti.Price );
					writer.Write( (string)ti.Description );
				}
			}
			else
				writer.Write( (int) 0 );

			if ( m_BidItems != null && m_BidItems.Count > 0 )
			{
				writer.Write( (int) m_BidItems.Count );

				for ( int i = 0; i < m_BidItems.Count; i++ )
				{
					BidByItem bbi = (BidByItem)m_BidItems[i];

					writer.Write( (Item) bbi.m_itemobj );
					writer.Write( (TimeSpan) bbi.m_duration );
					writer.Write( (DateTime) bbi.m_start );

					if ( bbi.m_byprice != null && bbi.m_byprice.Count > 0 )
					{
						writer.Write( (int) bbi.m_byprice.Count );
						foreach ( BidItem bi in bbi.m_byprice )
						{
							writer.Write( (Mobile) bi.m_bider );
							writer.Write( (int) bi.m_bid );
						}
					}
					else
						writer.Write( (int) 0 );
				}
			}
			else
				writer.Write( (int) 0 );
		}

		public override void Deserialize( GenericReader reader )
		{
			base.Deserialize( reader );
			int version = reader.ReadInt();

			m_Manager = (VendorManager)reader.ReadMobile();
			m_Owner = reader.ReadMobile();
			m_HoldBox = (VendorBox)reader.ReadItem();
			m_ShowBox = (VendorBox)reader.ReadItem();
			m_Currency = ScriptCompiler.FindTypeByName( reader.ReadString() );

			m_HoldGold = reader.ReadInt();
			m_CommRate = reader.ReadInt();
			m_IsComm = reader.ReadBool();
			m_AllowBid = reader.ReadBool();
			m_BondOnly = reader.ReadBool();

			m_CInfo = new CurrencyInfo( reader.ReadInt(), reader.ReadInt(), reader.ReadBool() );

			m_ShopItems = new Hashtable();
			for ( int i = reader.ReadInt(); i > 0; i-- )
			{
				Item item = reader.ReadItem();
				TradeItem ti = new TradeItem( (object)reader.ReadItem(), reader.ReadInt(), reader.ReadString() );

				m_ShopItems[item] = ti;
			}

			m_BidItems = new List<BidByItem>();
			for ( int i = reader.ReadInt(); i > 0; i-- )
			{
				BidByItem bbi = new BidByItem( (object)reader.ReadItem(), reader.ReadTimeSpan() );
				bbi.m_start = reader.ReadDateTime();

				for ( int j = reader.ReadInt(); j > 0; j-- )
				{
					bbi.m_lowest = 0;
					bbi.Add( reader.ReadMobile(), reader.ReadInt() );
				}

				m_BidItems.Add( bbi );
			}
		}


		private class ListBidEntry : ContextMenuEntry
		{
			private Mobile m_Mobile;
			private Mobile m_Vendor;

			public ListBidEntry( Mobile from, Mobile vendor ) : base( 0156, 3 )
			{
				m_Mobile = from;
				m_Vendor = vendor;

				Enabled = ( m_Mobile.Alive && m_Vendor is IHardsellable 
					&& ((IHardsellable)m_Vendor).BidItems != null && (((IHardsellable)m_Vendor).BidItems).Count > 0 );
			}

			public override void OnClick()
			{
				VendorManager.ListBidItems( m_Mobile, m_Vendor );
			}
		}

		private class SetupVendorEntry : ContextMenuEntry
		{
			private Mobile m_Mobile;
			private Mobile m_Vendor;

			public SetupVendorEntry( Mobile from, Mobile vendor ) : base( 0097, 3 )
			{
				m_Mobile = from;
				m_Vendor = vendor;

				Enabled = ( m_Mobile.Alive && ( m_Mobile.AccessLevel >= AccessLevel.GameMaster 
					|| ((WanderingTrader)m_Vendor).IsOwner( m_Mobile ) ) );
			}

			public override void OnClick()
			{
				m_Mobile.CloseGump( typeof( VendorSetupGump ) );
				m_Mobile.SendGump( new VendorSetupGump( m_Mobile, m_Vendor ) );
			}
		}

		private class AddVendorItemEntry : ContextMenuEntry
		{
			private Mobile m_Mobile;
			private Mobile m_Vendor;

			public AddVendorItemEntry( Mobile from, Mobile vendor ) : base( 0175, 3 )
			{
				m_Mobile = from;
				m_Vendor = vendor;

				Enabled = ( m_Mobile.Alive && ( m_Mobile.AccessLevel >= AccessLevel.GameMaster 
					|| ((WanderingTrader)m_Vendor).IsOwner( m_Mobile ) ) );
			}

			public override void OnClick()
			{
				VendorManager.AddHardItem( m_Mobile, m_Vendor );
			}
		}

		private class BuyVendorItemEntry : ContextMenuEntry
		{
			private Mobile m_Mobile;
			private Mobile m_Vendor;

			public BuyVendorItemEntry( Mobile from, Mobile vendor ) : base( 0146, 3 )
			{
				m_Mobile = from;
				m_Vendor = vendor;

				Enabled = ( m_Mobile.Alive && m_Vendor is IHardsellable && ((IHardsellable)m_Vendor).HoldBox != null 
					&& ((IHardsellable)m_Vendor).ShopItems != null && (((IHardsellable)m_Vendor).ShopItems).Count > 0 );
			}

			public override void OnClick()
			{
				VendorManager.SellHardItem( m_Mobile, m_Vendor );
			}
		}

	}
}